#ifdef __GNUG__
#pragma implementation
#endif

#include "WindowBorder.h"
#include "../LOOKS/MotifLook.h"

#include "Class.h"
#include "Buttons.h"
#include "Box.h"
#include "Window.h"
#include "TextItem.h"
#include "Menu.h"
#include "Env.h"
#include "OrdColl.h"
#include "Math.h"
#include "PopupItem.h"

//---- MotifIconBorder --------------------------------------------------------------

class MotifIconBorder: public WindowBorder {
	int border;
public:
	MetaDef(MotifIconBorder);
	MotifIconBorder(VObject *title, VObject *inner);
	Command *DoLeftButtonDownCommand(Point p, Token, int);
	void Draw(Rectangle);
	Metric GetMinSize();
	void SetOrigin(Point at);
	void SetExtent(Point e);
};

//---- MotifWindowButton ------------------------------------------------------------

class MotifWindowButton: public PullDownButton {
	int type;
public:
	MetaDef(MotifWindowButton);
	MotifWindowButton(int id, int i, const char *title= 0);
	Metric GetMinSize()
		{ return Metric(Point(23), 15); }
	void DrawHighlight(Rectangle)
		{ }
	void DrawInner(Rectangle, bool);
	void SetExtent(Point e);
	void SetOrigin(Point at);
	void SetString(const char *t);
	Command *DoLeftButtonDownCommand(Point lp, Token t, int cl);
};

//---- WindowBorder ------------------------------------------------------------

class MotifWindowBorder: public WindowBorder {
	MotifWindowButton *ti;
	int border;
public:
	MetaDef(MotifWindowBorder);

	MotifWindowBorder(bool fixed, VObject *title, VObject *inner, MotifWindowButton *ti= 0);
	void Draw(Rectangle);
	Metric GetMinSize();
	void SetOrigin(Point at);
	void SetExtent(Point e);
	Command *DoLeftButtonDownCommand(Point p, Token, int);
	void SetTitle(const char*);
};

//---- MotifWindowButton ------------------------------------------------------------

NewMetaImpl0(MotifWindowButton,PullDownButton);

MotifWindowButton::MotifWindowButton(int id, int i, const char *title)
							: PullDownButton(id, 0)
{
	SetFlag(eVObjHFixed|eVObjVFixed);
	type= i;
	if (type == 0) {
		menu= new Menu("Window", FALSE);
		menu->AppendItems(
				"Minimize",     cCOLLAPSE,
				"Top",          cTOP,
				"Lower",        cBOTTOM,
				"-",
				"Hide",         4711,
				"Show",         4712,
				"-",
				"Redisplay",    cREDISPLAY,
				0
		);
	}
	if (title) {
		VObject *ti= new TextItem(title);
		ti->SetFlag(eVObjHFixed|eVObjVFixed);
		ResetFlag(eVObjHFixed);
		Add(ti);
	}
}

void MotifWindowButton::SetString(const char *t)
{
	TextItem *ti= (TextItem*) At(0);
	if (ti)
		ti->SetString(t, TRUE);
	SetExtent(GetExtent());
	SetOrigin(GetOrigin());
	ForceRedraw();
}

void MotifWindowButton::SetExtent(Point e)
{
	VObject::SetExtent(e);
	if (Size() > 0)
		At(0)->CalcExtent();
}

void MotifWindowButton::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	if (Size() > 0)
		At(0)->Align(at, GetExtent(), (VObjAlign) (eVObjHCenter|eVObjVCenter));
}

void MotifWindowButton::DrawInner(Rectangle, bool highlight)
{
	Point pp;
	Rectangle r(contentRect);
	switch (type) {
	case 0:
		pp= Point(4, 9);
		break;
	case 1:
		pp= gPoint0;
		break;
	case 2:
		pp= Point(9, 9);
		break;
	case 3:
		pp= Point(4, 4);
		break;
	}
	if (highlight) {
		GrPaintRect(r, gMotif->recessed);
		BevelRect(r, 1, FALSE, gMotif->dark, gMotif->light);
	} else
		BevelRect(r, 1, TRUE, gMotif->dark, gMotif->light);
	if (pp != gPoint0)
		BevelRect(r.Inset(pp), 1, TRUE, gMotif->dark, gMotif->light);

	Button::Draw(r);
}

Command *MotifWindowButton::DoLeftButtonDownCommand(Point lp, Token t, int cl)
{
	if (Size() > 0) {
		Window *win= GetWindow();
		Command *wm= new VObjectMover(win, win->ScreenRect(), gPoint1, eCrsMoveHand, 4);
		wm->SetFlag(eCmdFullScreen);
		wm->SetType(eCmdTypeNoChange);
		return wm;
	}
	return Button::DoLeftButtonDownCommand(lp, t, cl);
}

//---- MotifWindowBorder ------------------------------------------------------------

NewMetaImpl(MotifWindowBorder,WindowBorder, (TB(fixed)));

MotifWindowBorder::MotifWindowBorder(bool fix, VObject *title, VObject *inner,
			MotifWindowButton *tit) : WindowBorder(fix, title, inner)
{
	border= fixed ? 8 : 10;
	ti= tit;
}

void MotifWindowBorder::SetTitle(const char *t)
{
	if (ti)
		ti->SetString(t);
}

Metric MotifWindowBorder::GetMinSize()
{
	Point e= At(0)->GetMinSize().extent + 2*border;
	if (Size() > 1) {
		Metric m(At(1)->GetMinSize());
		e.x= Math::Max(e.x, m.extent.x);
		e.y+= m.extent.y;
	}
	return e;
}

void MotifWindowBorder::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	at+= border;
	if (Size() > 1) {
		At(1)->SetOrigin(at-gPoint1);
		at.y+= At(1)->Height();
	}
	At(0)->SetOrigin(at);
}

void MotifWindowBorder::SetExtent(Point e)
{
	VObject::SetExtent(e);
	e-= 2*border;
	if (Size() > 1) {
		int h= At(1)->GetMinSize().extent.y;
		At(1)->SetExtent(Point(e.x+2, h));
		e.y-= h;
	}
	At(0)->SetExtent(e);
}

void MotifWindowBorder::Draw(Rectangle dr)
{
	Rectangle ir(At(0)->contentRect);

	GrPaintRect(ir, gLook->backgroundColor);
	if (! ir.ContainsRect(dr)) {
		Ink *dark= gMotif->dark,
			*light= gMotif->light;
		
		Rectangle rl[4];
		int n= Difference(rl, dr, ir);
		for (int i= 0; i < n; i++)
			GrPaintRect(rl[i], gMotif->backgroundColor);
		
		BevelRect(contentRect, 2, TRUE, dark, light);
		if (Size() > 1) {
			int h= At(1)->contentRect.extent.y;
			Rectangle rrr(contentRect);
			BevelRect(contentRect.Inset(border-2), 1, FALSE, dark, light);
			rrr.origin.y+= h;
			rrr.extent.y-= h;
			BevelRect(rrr.Inset(border-1), 1, FALSE, dark, light);
		} else {
			BevelRect(contentRect.Inset(border-2), 2, FALSE, dark, light);
		}

		if (!fixed) {
			int l= border-1 + At(1)->Height()-1,
				x= 1, y= 1, ll= border-4,
				w= contentRect.extent.x,
				h= contentRect.extent.y;
		
			for (int i= 0; i < 2; i++) {
				BevelLine(Point(x,     l),     Point(x+ll,  l),     FALSE, dark, light);
				BevelLine(Point(x,     h-l-2), Point(x+ll,  h-l-2), FALSE, dark, light);
				BevelLine(Point(l,     y),     Point(l,     y+ll),  FALSE, dark, light);
				BevelLine(Point(w-l-2, y),     Point(w-l-2, y+ll),  FALSE, dark, light);
				x= w-border+1;
				y= h-border+1;
			}
		}
	}
	CompositeVObject::Draw(dr);
}

Command *MotifWindowBorder::DoLeftButtonDownCommand(Point p, Token, int)
{
	Command *wm= gNoChanges;
	if (!At(0)->contentRect.ContainsPoint(p)) {
		Window *win= GetWindow();

		win->Top();
		if (!fixed)
			wm= new VObjectStretcher(win, win->ScreenRect());
		else
			wm= new VObjectMover(win, win->ScreenRect(), gPoint1, eCrsMoveHand, 4);

		wm->SetFlag(eCmdFullScreen);
		wm->SetType(eCmdTypeNoChange);
	}
	return wm;
}

//---- MotifIconBorder --------------------------------------------------------------

NewMetaImpl0(MotifIconBorder,WindowBorder);

MotifIconBorder::MotifIconBorder(VObject *title, VObject *inner)
									: WindowBorder(TRUE, title, inner)
{
	border= 6;
}

Metric MotifIconBorder::GetMinSize()
{
	Point e(64+2*border);
	Point m(At(1)->GetMinSize().extent+2*border);
	e.x= Math::Max(e.x, m.x);
	e.y+= m.y;
	return e;
}

void MotifIconBorder::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	Rectangle r(contentRect);
	int h= At(1)->Height() + 2*border;

	r.extent.y-= h;
	At(0)->Align(r.origin, r.extent, (VObjAlign) (eVObjHCenter|eVObjVCenter));

	r.origin.y= r.extent.y;
	r.extent.y= h;
	At(1)->Align(r.origin, r.extent, (VObjAlign) (eVObjHCenter|eVObjVBottom));
}

void MotifIconBorder::SetExtent(Point e)
{
	VObject::SetExtent(e);
	At(0)->CalcExtent();
	At(1)->CalcExtent();
}

void MotifIconBorder::Draw(Rectangle r)
{
	int h= At(1)->Height() + 2*border;
	Rectangle rr(contentRect);
	// GrPaintRect(r, gMotif->backgroundColor);
	rr.extent.y-= h;
	BevelRect(rr, 2, TRUE, gMotif->dark, gMotif->light);
	Rectangle rrr(rr.Inset(6));
	BevelRect(rrr, 1, FALSE, gMotif->dark, gMotif->light);
	rr.origin.y= rr.extent.y;
	rr.extent.y= h;
	BevelRect(rr, 2, TRUE, gMotif->dark, gMotif->light);

	CompositeVObject::Draw(r);
}

Command *MotifIconBorder::DoLeftButtonDownCommand(Point, Token, int clicks)
{
	Window *win= GetWindow();
	if (win && clicks >= 2) {
		win->Iconize();
		return gNoChanges;
	}
	Command *wm= new VObjectMover(win, win->ScreenRect(), gPoint4, eCrsMoveHand, 4);
	wm->SetFlag(eCmdFullScreen);
	wm->SetType(eCmdTypeNoChange);
	return wm;
}

//---- entrypoint --------------------------------------------------------------

VObject *MakeWindowBorder(WindowType wt, VObject *in, char *title,
													bool blocked, bool fixed)
{
	VObject *t;
	MotifWindowButton *ti= 0;
	OrdCollection *col= new OrdCollection;

	switch (wt) {

	case eWinIcon: // Icon
		t= new TextItem(cIdIconLabel, title);
		t->SetFlag(eVObjHFixed);
		return new MotifIconBorder(t, in);

	case eWinPlain: // plain window ala Window
		return in;
		
	case eWinStandard:
		if (title == 0)
			title= "";
		col->Add(new MotifWindowButton(cIdCloseBox, 0));
		col->Add(ti= new MotifWindowButton(cIdWindowTitle, 1, title));
		col->Add(new MotifWindowButton(cIdCloseBox, 2));
		col->Add(new MotifWindowButton(cIdBottom, 3));
		return new MotifWindowBorder(fixed,
						new Expander(cIdNone, eHor, gPoint0, col), in, ti);

	case eWinDialog:
		if (title || !fixed || !blocked) {
			if (!blocked)
				col->Add(new MotifWindowButton(cIdCloseBox, 0));
			if (title)
				col->Add(ti= new MotifWindowButton(cIdWindowTitle, 1, title));
			if (!blocked)
				col->Add(new MotifWindowButton(cIdCloseBox, 2));
			if (!blocked && !fixed)
				col->Add(new MotifWindowButton(cIdBottom, 3));
			return new MotifWindowBorder(fixed,
						new Expander(cIdNone, eHor, gPoint0, col), in, ti);
		}
		return new MotifWindowBorder(fixed, 0, in);
		
	default:
		return in;
	}
}

